﻿//Copyright (c) 2007-2012, Adolfo Marinucci
//All rights reserved.

//Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
//following conditions are met:

//* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

//* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
//disclaimer in the documentation and/or other materials provided with the distribution.

//* Neither the name of Adolfo Marinucci nor the names of its contributors may be used to endorse or promote products
//derived from this software without specific prior written permission.

//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
//INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
//STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
//EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

using System.Linq;
using System.Windows;
using System.Windows.Media;
using AvalonDock.Layout;

namespace AvalonDock.Controls
{
    internal class DocumentPaneDropAsAnchorableTarget : DropTarget<LayoutDocumentPaneControl>
    {
        internal DocumentPaneDropAsAnchorableTarget(LayoutDocumentPaneControl paneControl, Rect detectionRect, DropTargetType type)
            : base(paneControl, detectionRect, type)
        {
            _targetPane = paneControl;
        }

        internal DocumentPaneDropAsAnchorableTarget(LayoutDocumentPaneControl paneControl, Rect detectionRect, DropTargetType type, int tabIndex)
            : base(paneControl, detectionRect, type)
        {
            _targetPane = paneControl;
            _tabIndex = tabIndex;
        }

        LayoutDocumentPaneControl _targetPane;

        int _tabIndex = -1;

        protected override void Drop(LayoutAnchorableFloatingWindow floatingWindow)
        {
            ILayoutDocumentPane targetModel = _targetPane.Model as ILayoutDocumentPane;

            switch (Type)
            {
                case DropTargetType.DocumentPaneDockAsAnchorableBottom:

                    #region DropTargetType.DocumentPaneDockAsAnchorableBottom

                    {
                        LayoutPanel parentGroupPanel = null;
                        var parentGroup = targetModel.Parent as LayoutDocumentPaneGroup;
                        if (parentGroup != null)
                            parentGroupPanel = parentGroup.Parent as LayoutPanel;
                        else
                            parentGroupPanel = targetModel.Parent as LayoutPanel;

                        if (parentGroupPanel != null &&
                            parentGroupPanel.Orientation == System.Windows.Controls.Orientation.Vertical)
                        {
                            parentGroupPanel.Children.Insert(
                                parentGroupPanel.IndexOfChild(parentGroup != null ? parentGroup : targetModel) + 1,
                                floatingWindow.RootPanel);
                        }
                        else if (parentGroupPanel != null)
                        {
                            var newParentPanel = new LayoutPanel() { Orientation = System.Windows.Controls.Orientation.Vertical };
                            parentGroupPanel.ReplaceChild(parentGroup != null ? parentGroup : targetModel, newParentPanel);
                            newParentPanel.Children.Add(parentGroup != null ? parentGroup : targetModel);
                            newParentPanel.Children.Add(floatingWindow.RootPanel);
                        }
                        else
                        {
                            // Grzegorz Russek 2012-07-11 Fix Start
                            DockingManager manager = floatingWindow.Root.Manager;

                            if (manager.Layout.RootPanel.Orientation != System.Windows.Controls.Orientation.Vertical &&
                                manager.Layout.RootPanel.Children.Count == 1)
                                manager.Layout.RootPanel.Orientation = System.Windows.Controls.Orientation.Vertical;

                            if (manager.Layout.RootPanel.Orientation == System.Windows.Controls.Orientation.Vertical)
                            {
                                var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup;
                                if (layoutAnchorablePaneGroup != null &&
                                    layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Vertical)
                                {
                                    for (int i = 0; i < layoutAnchorablePaneGroup.Children.Count; i++)
                                        manager.Layout.RootPanel.Children.Add(layoutAnchorablePaneGroup.Children[i]);
                                }
                                else
                                    manager.Layout.RootPanel.Children.Add(floatingWindow.RootPanel);
                            }
                            else
                            {
                                var newOrientedPanel = new LayoutPanel()
                                {
                                    Orientation = System.Windows.Controls.Orientation.Vertical
                                };

                                newOrientedPanel.Children.Add(manager.Layout.RootPanel);
                                newOrientedPanel.Children.Add(floatingWindow.RootPanel);

                                manager.Layout.RootPanel = newOrientedPanel;
                            }
                            // Grzegorz Russek 2012-07-11 Fix End
                        }
                    }
                    break;

                    #endregion DropTargetType.DocumentPaneDockAsAnchorableBottom

                case DropTargetType.DocumentPaneDockAsAnchorableTop:

                    #region DropTargetType.DocumentPaneDockAsAnchorableTop

                    {
                        LayoutPanel parentGroupPanel = null;
                        var parentGroup = targetModel.Parent as LayoutDocumentPaneGroup;
                        if (parentGroup != null)
                            parentGroupPanel = parentGroup.Parent as LayoutPanel;
                        else
                            parentGroupPanel = targetModel.Parent as LayoutPanel;

                        if (parentGroupPanel != null &&
                            parentGroupPanel.Orientation == System.Windows.Controls.Orientation.Vertical)
                        {
                            parentGroupPanel.Children.Insert(
                                parentGroupPanel.IndexOfChild(parentGroup != null ? parentGroup : targetModel),
                                floatingWindow.RootPanel);
                        }
                        else if (parentGroupPanel != null)
                        {
                            var newParentPanel = new LayoutPanel() { Orientation = System.Windows.Controls.Orientation.Vertical };
                            parentGroupPanel.ReplaceChild(parentGroup != null ? parentGroup : targetModel, newParentPanel);
                            newParentPanel.Children.Add(parentGroup != null ? parentGroup : targetModel);
                            newParentPanel.Children.Insert(0, floatingWindow.RootPanel);
                        }
                        else
                        {
                            // Grzegorz Russek 2012-07-11 Fix Start
                            DockingManager manager = floatingWindow.Root.Manager;

                            if (manager.Layout.RootPanel.Orientation != System.Windows.Controls.Orientation.Vertical &&
                                manager.Layout.RootPanel.Children.Count == 1)
                                manager.Layout.RootPanel.Orientation = System.Windows.Controls.Orientation.Vertical;

                            if (manager.Layout.RootPanel.Orientation == System.Windows.Controls.Orientation.Vertical)
                            {
                                var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup;
                                if (layoutAnchorablePaneGroup != null &&
                                    layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Vertical)
                                {
                                    for (int i = 0; i < layoutAnchorablePaneGroup.Children.Count; i++)
                                        manager.Layout.RootPanel.Children.Insert(i, layoutAnchorablePaneGroup.Children[i]);
                                }
                                else
                                    manager.Layout.RootPanel.Children.Insert(0, floatingWindow.RootPanel);
                            }
                            else
                            {
                                var newOrientedPanel = new LayoutPanel()
                                {
                                    Orientation = System.Windows.Controls.Orientation.Vertical
                                };

                                newOrientedPanel.Children.Add(floatingWindow.RootPanel);
                                newOrientedPanel.Children.Add(manager.Layout.RootPanel);

                                manager.Layout.RootPanel = newOrientedPanel;
                            }
                            // Grzegorz Russek 2012-07-11 Fix End
                        }
                    }
                    break;

                    #endregion DropTargetType.DocumentPaneDockAsAnchorableTop

                case DropTargetType.DocumentPaneDockAsAnchorableLeft:

                    #region DropTargetType.DocumentPaneDockAsAnchorableLeft

                    {
                        LayoutPanel parentGroupPanel = null;
                        var parentGroup = targetModel.Parent as LayoutDocumentPaneGroup;
                        if (parentGroup != null)
                            parentGroupPanel = parentGroup.Parent as LayoutPanel;
                        else
                            parentGroupPanel = targetModel.Parent as LayoutPanel;

                        if (parentGroupPanel != null &&
                            parentGroupPanel.Orientation == System.Windows.Controls.Orientation.Horizontal)
                        {
                            parentGroupPanel.Children.Insert(
                                parentGroupPanel.IndexOfChild(parentGroup != null ? parentGroup : targetModel),
                                floatingWindow.RootPanel);
                        }
                        else if (parentGroupPanel != null)
                        {
                            var newParentPanel = new LayoutPanel() { Orientation = System.Windows.Controls.Orientation.Horizontal };
                            parentGroupPanel.ReplaceChild(parentGroup != null ? parentGroup : targetModel, newParentPanel);
                            newParentPanel.Children.Add(parentGroup != null ? parentGroup : targetModel);
                            newParentPanel.Children.Insert(0, floatingWindow.RootPanel);
                        }
                        else
                        {
                            // Grzegorz Russek 2012-07-11 Fix Start
                            DockingManager manager = floatingWindow.Root.Manager;

                            if (manager.Layout.RootPanel.Orientation != System.Windows.Controls.Orientation.Horizontal &&
                                manager.Layout.RootPanel.Children.Count == 1)
                                manager.Layout.RootPanel.Orientation = System.Windows.Controls.Orientation.Horizontal;

                            if (manager.Layout.RootPanel.Orientation == System.Windows.Controls.Orientation.Horizontal)
                            {
                                var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup;
                                if (layoutAnchorablePaneGroup != null &&
                                    layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Horizontal)
                                {
                                    for (int i = 0; i < layoutAnchorablePaneGroup.Children.Count; i++)
                                        manager.Layout.RootPanel.Children.Insert(i, layoutAnchorablePaneGroup.Children[i]);
                                }
                                else
                                    manager.Layout.RootPanel.Children.Insert(0, floatingWindow.RootPanel);
                            }
                            else
                            {
                                var newOrientedPanel = new LayoutPanel()
                                {
                                    Orientation = System.Windows.Controls.Orientation.Horizontal
                                };

                                newOrientedPanel.Children.Add(floatingWindow.RootPanel);
                                newOrientedPanel.Children.Add(manager.Layout.RootPanel);

                                manager.Layout.RootPanel = newOrientedPanel;
                            }
                            // Grzegorz Russek 2012-07-11 Fix End
                        }
                    }
                    break;

                    #endregion DropTargetType.DocumentPaneDockAsAnchorableLeft

                case DropTargetType.DocumentPaneDockAsAnchorableRight:

                    #region DropTargetType.DocumentPaneDockAsAnchorableRight

                    {
                        LayoutPanel parentGroupPanel = null;
                        var parentGroup = targetModel.Parent as LayoutDocumentPaneGroup;
                        if (parentGroup != null)
                            parentGroupPanel = parentGroup.Parent as LayoutPanel;
                        else
                            parentGroupPanel = targetModel.Parent as LayoutPanel;

                        if (parentGroupPanel != null &&
                            parentGroupPanel.Orientation == System.Windows.Controls.Orientation.Horizontal)
                        {
                            parentGroupPanel.Children.Insert(
                                parentGroupPanel.IndexOfChild(parentGroup != null ? parentGroup : targetModel) + 1,
                                floatingWindow.RootPanel);
                        }
                        else if (parentGroupPanel != null)
                        {
                            var newParentPanel = new LayoutPanel() { Orientation = System.Windows.Controls.Orientation.Horizontal };
                            parentGroupPanel.ReplaceChild(parentGroup != null ? parentGroup : targetModel, newParentPanel);
                            newParentPanel.Children.Add(parentGroup != null ? parentGroup : targetModel);
                            newParentPanel.Children.Add(floatingWindow.RootPanel);
                        }
                        else
                        {
                            // Grzegorz Russek 2012-07-11 Fix Start
                            DockingManager manager = floatingWindow.Root.Manager;

                            if (manager.Layout.RootPanel.Orientation != System.Windows.Controls.Orientation.Horizontal &&
                                manager.Layout.RootPanel.Children.Count == 1)
                                manager.Layout.RootPanel.Orientation = System.Windows.Controls.Orientation.Horizontal;

                            if (manager.Layout.RootPanel.Orientation == System.Windows.Controls.Orientation.Horizontal)
                            {
                                var layoutAnchorablePaneGroup = floatingWindow.RootPanel as LayoutAnchorablePaneGroup;
                                if (layoutAnchorablePaneGroup != null &&
                                    layoutAnchorablePaneGroup.Orientation == System.Windows.Controls.Orientation.Horizontal)
                                {
                                    for (int i = 0; i < layoutAnchorablePaneGroup.Children.Count; i++)
                                        manager.Layout.RootPanel.Children.Add(layoutAnchorablePaneGroup.Children[i]);
                                }
                                else
                                    manager.Layout.RootPanel.Children.Add(floatingWindow.RootPanel);
                            }
                            else
                            {
                                var newOrientedPanel = new LayoutPanel()
                                {
                                    Orientation = System.Windows.Controls.Orientation.Horizontal
                                };

                                newOrientedPanel.Children.Add(manager.Layout.RootPanel);
                                newOrientedPanel.Children.Add(floatingWindow.RootPanel);

                                manager.Layout.RootPanel = newOrientedPanel;
                            }
                            // Grzegorz Russek 2012-07-11 Fix End
                        }
                    }
                    break;

                    #endregion DropTargetType.DocumentPaneDockAsAnchorableRight
            }

            base.Drop(floatingWindow);
        }

        public override System.Windows.Media.Geometry GetPreviewPath(OverlayWindow overlayWindow, LayoutFloatingWindow floatingWindowModel)
        {
            Rect targetScreenRect;
            ILayoutDocumentPane targetModel = _targetPane.Model as ILayoutDocumentPane;
            var manager = targetModel.Root.Manager;

            if (targetModel.Parent is LayoutDocumentPaneGroup)
            {
                var parentGroup = targetModel.Parent as LayoutDocumentPaneGroup;
                var documentPaneGroupControl = manager.FindLogicalChildren<LayoutDocumentPaneGroupControl>().First(d => d.Model == parentGroup);
                targetScreenRect = documentPaneGroupControl.GetScreenArea();
            }
            else
            {
                var documentPaneControl = manager.FindLogicalChildren<LayoutDocumentPaneControl>().First(d => d.Model == targetModel);
                targetScreenRect = documentPaneControl.GetScreenArea();
            }

            switch (Type)
            {
                case DropTargetType.DocumentPaneDockAsAnchorableBottom:
                    {
                        targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top);
                        targetScreenRect.Offset(0.0, targetScreenRect.Height - targetScreenRect.Height / 3.0);
                        targetScreenRect.Height /= 3.0;
                        return new RectangleGeometry(targetScreenRect);
                    }
                case DropTargetType.DocumentPaneDockAsAnchorableTop:
                    {
                        targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top);
                        targetScreenRect.Height /= 3.0;
                        return new RectangleGeometry(targetScreenRect);
                    }
                case DropTargetType.DocumentPaneDockAsAnchorableRight:
                    {
                        targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top);
                        targetScreenRect.Offset(targetScreenRect.Width - targetScreenRect.Width / 3.0, 0.0);
                        targetScreenRect.Width /= 3.0;
                        return new RectangleGeometry(targetScreenRect);
                    }
                case DropTargetType.DocumentPaneDockAsAnchorableLeft:
                    {
                        targetScreenRect.Offset(-overlayWindow.Left, -overlayWindow.Top);
                        targetScreenRect.Width /= 3.0;
                        return new RectangleGeometry(targetScreenRect);
                    }
            }

            return null;
        }
    }
}